package com.tanger.common.socket;

import com.tanger.common.utils.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.websocket.Session;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserCaches {

    /**
     * uid(UUID) -> session
     */
    private static Map<String, Session> usm = new ConcurrentHashMap<>();

    /**
     * sid(sessionId) -> uid(UUID)
     */
    private static Map<String, String> sum = new ConcurrentHashMap<>();

    /**
     * 用户信息 redis 缓存 key
     * SAAS-POI:ISSU-PUSH:pId:bId:uid(UUID)
     */
    private static final String USER_KEY = "SAAS-POI:ISSU-PUSH:%s:%s:%s";

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public List<Session> findUsers(String pId,String bId) {
        List<NoticePushUser> pUsers = findAll(pId, bId);
        List<String> sIds = pUsers.stream().map(NoticePushUser::getSid).collect(Collectors.toList());

        List<Session> users = new ArrayList<>();
        Iterator<Map.Entry<String,String>> sMap = sum.entrySet().iterator();
        List<String> uIds = new ArrayList<>();
        while (sMap.hasNext()) {
            Map.Entry<String,String> entry = sMap.next();
            if (sIds.stream().anyMatch(i -> i.equals(entry.getKey()))) {
                uIds.add(entry.getValue());
            }
        }

        if (CollectionUtils.isEmpty(uIds)) return users;

        Iterator<Map.Entry<String,Session>> gMap = usm.entrySet().iterator();
        while (gMap.hasNext()) {
            Map.Entry<String,Session> entry = gMap.next();
            if (uIds.stream().anyMatch(j -> j.equals(entry.getKey()))) {
                users.add(entry.getValue());
            }
        }
        return users;
    }

    /**
     * 获取所有用户信息
     * @param pId
     * @param bId
     * @return
     */
    public List<NoticePushUser> findAll(String pId, String bId) {
        Set<String> keys = stringRedisTemplate.keys(userKey(pId, bId,"*"));
        return keys.stream()
                .map(this::findValue)
                .collect(Collectors.toList());
    }

    protected NoticePushUser findValue(String key) {
        if (!Strings.isEmpty(key)) {
            String data = stringRedisTemplate.opsForValue().get(key);
            return JSON.parse(data, NoticePushUser.class);
        }
        return null;
    }

    /**
     * 获取用户id
     * @param session
     * @return
     */
    public Long getUser(String pId,String bId, Session session) {
        // 获取用户信息
        String uid = sum.get(session.getId());
        if (Strings.isEmpty(uid)) return null;
        String data = stringRedisTemplate.opsForValue().get(userKey(pId, bId, uid));
        if (Strings.isEmpty(data)) return null;
        NoticePushUser user = JSON.parse(data, NoticePushUser.class);
        return Objects.isNull(user)? null:user.getUid();
    }

    /**
     * @param session
     */
    public NoticePushUser create(String pId, String bId, Session session) {
        // 初始化用户信息
        String uid = UUID.randomUUID().toString().replace("-", "");
        NoticePushUser user = new NoticePushUser(session.getId(), Long.valueOf(uid));
        String se = JSON.stringify(user);
        // 缓存用户，session
        stringRedisTemplate.opsForValue().set(userKey(pId, bId, uid), se, 24, TimeUnit.HOURS);
        usm.put(uid, session);
        sum.put(session.getId(), uid);
        return user;
    }

    /**
     * @param session
     */
    public NoticePushUser remove(String pId, String bId, Session session) {
        String uid = sum.get(session.getId());
        if (!usm.containsKey(uid)) return new NoticePushUser();

        // 获取用户信息
        String data = stringRedisTemplate.opsForValue().get(userKey(pId, bId, uid));
        if (Strings.isEmpty(data)) return new NoticePushUser();
        NoticePushUser user = JSON.parse(data, NoticePushUser.class);

        // 移除用户缓存，session 缓存
        stringRedisTemplate.delete(userKey(pId, bId, uid));
        usm.remove(uid);
        sum.remove(session.getId(), uid);
        log.info("[issu-push] on close connect; user: {}", uid);
        return user;
    }

    public String userKey(String pId,String bId, String uId) {
        return String.format(USER_KEY, pId, bId, uId);
    }
}
